package com.chebaohui.iqs.service.impl;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.ModelAndView;

import com.alibaba.druid.support.logging.Log;
import com.alibaba.druid.support.logging.LogFactory;
import com.alibaba.fastjson.JSONObject;
import com.chebaohui.iqs.entity.db.DbParam;
import com.chebaohui.iqs.sdk.OkHttp;
import com.chebaohui.iqs.service.ChinaUnionServie;
import com.chebaohui.iqs.service.DBService;
import com.chebaohui.iqs.service.impl.deal.union.profess.UnionPrice;
import com.chebaohui.iqs.service.impl.deal.union.sdk.UnionValidate;
import com.chebaohui.iqs.service.impl.deal.union.util.PayConsume;
import com.chebaohui.iqs.sign.SignParam;
import com.chebaohui.iqs.sign.SignUtil;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class ChinaUnionServieImpl implements ChinaUnionServie {
	public static final String union_file_path = "test";// 银联相关文件放在config下union的哪个目录下

	/**
	 * log:日志输出
	 */
	private static Log log = LogFactory.getLog(ChinaUnionServieImpl.class);
	@Autowired
	private DBService db;

	@Override
	public void price(HttpServletRequest request, HttpServletResponse response, String orderSid) {
		try {
			response.setContentType("text/html; charset=" + "UTF-8");

			log.info("订单:" + orderSid + ",支付调起....");
			String amoutn = "10000";// 测试金额 // http://a2c2e8a6.ngrok.io/china/newUnion/money?orderSid=cqhr20171227175211

			{// 本地测试时 该{}下的语句不执行
				DbParam sql = new DbParam();
				sql.setcType("pay");
				sql.setSpare(orderSid);
				List<DbParam> res = db.query(sql);
				if (null == res || res.isEmpty() || res.size() < 1) {
					log.error(orderSid + ",此订单不存在");
					response.getWriter().write(errorHtml("没有此:" + orderSid + "订单..."));
				}
				JSONObject pays = JSONObject.parseObject(res.get(0).getDatas());

				// 订单已支付
				if ("three".equals(res.get(0).getNumType())) {
					response.getWriter().write(errorHtml("订单:" + orderSid + ",已支付!!!"));
				}

				long reserve = Long.valueOf(res.get(0).getReserve())
						+ 1000 * 60 * Integer.valueOf(pays.getString("timeOut"));

				// 订单支付超时
				if (new Date().getTime() > reserve) {
					log.error(orderSid + ",订单支付超时，请重新生成订单");
					response.getWriter().write(errorHtml("订单:" + orderSid + ",订单支付超时，请重新生成订单!!!"));
				}

				if ("one".equals(res.get(0).getNumType())) {// 更新数据库订单状态
					DbParam upedate = res.get(0);
					upedate.setNumType("two");
					db.undate(upedate);
				}
				amoutn = pays.getString("amount");// 金额单位分
			}

			/** 生成自动跳转的Html表单 **/
			String fromHtml = new UnionPrice().getPriceHtml(orderSid, amoutn);

			response.getWriter().write(fromHtml);
		} catch (Exception e) {
			try {
				response.getWriter().write(errorHtml(e.getMessage()));
			} catch (Exception e2) {
				e2.printStackTrace();
			}
		}
	}

	@Override
	public void back(final HttpServletRequest request, final HttpServletResponse response) {
		try {
			// 获取银联通知服务器发送的后台通知参数
			Map<String, String> back = getAllRequestParam(request);
			log.info("银联通知服务器发送数据:" + JSONObject.toJSONString(back));

			boolean validate = UnionValidate.validates(back, "UTF-8", PayConsume.getUnion(union_file_path));
			log.info("银联通知服务器发送数据验证结果:" + validate);

			if (validate) {// 本地测试时 该if下的语句不执行
				String orderSid = back.get("orderId");// 订单号
				String txnAmt = back.get("txnAmt");// 订单金额,分

				DbParam sql = new DbParam();
				sql.setcType("pay");
				sql.setSpare(orderSid);
				sql.setNumType("two");

				boolean ret = true;// 订单是否已回调
				List<DbParam> res = db.query(sql);
				if (null == res || res.isEmpty() || res.size() < 1) {
					log.error(orderSid + ",该状态的订单不存在");
					ret = false;
				}

				if (ret) {
					JSONObject pays = JSONObject.parseObject(res.get(0).getDatas());

					DbParam update = res.get(0);
					JSONObject date = new JSONObject();
					date.put("pays", pays);
					date.put("back", back);
					update.setNumType("three");
					update.setDatas(date.toJSONString());
					db.undate(update);

					String respCode = back.get("respCode");// 应答码，00表示成功；

					BigDecimal amount = new BigDecimal(txnAmt);
					amount = amount.divide(new BigDecimal("100"));

					if ("00".equals(respCode))// 支付成功回调业务方
						returnBack(orderSid, amount.toString(), pays.getString("backUrl"), "001", "3");
				}
			}
		} catch (Exception e) {
			log.error("银联通知服务器发送数据处理异常:" + e.getMessage());
		} finally {
			try {
				// 返回给银联服务器http 200 状态码
				response.getWriter().print("ok");
			} catch (Exception e) {
				log.error("银联通知服务器发送数据处理异常<返回银联>:" + e.getMessage());
			}
		}

	}

	@Override
	public ModelAndView front(final HttpServletRequest request, final HttpServletResponse response) {
		try {
			Map<String, String> front = getAllRequestParam(request);
			log.info("银联页面转调发送数据:" + JSONObject.toJSONString(front));
			boolean validate = UnionValidate.validates(front, "UTF-8", PayConsume.getUnion(union_file_path));
			log.info("银联页面转调发送数据验证结果:" + validate);

			if (validate) {// 本地测试时 该if下的语句不执行
				String txnAmt = front.get("txnAmt");// 订单金额,分
				String orderSid = front.get("orderId");// 订单号
				DbParam sql = new DbParam();
				sql.setcType("pay");
				sql.setSpare(orderSid);

				BigDecimal amount = new BigDecimal(txnAmt);
				amount = amount.divide(new BigDecimal("100"));
				List<DbParam> res = db.query(sql);
				if (null == res || res.isEmpty() || res.size() < 1) {
					log.error(orderSid + ",该状态的订单不存在");
					ModelAndView view = back_return(false);
					view.addObject("out_trade_no", front.get("orderId"));// 订单号
					view.addObject("grade_time", front.get("txnTime"));// 订单发起时间
					view.addObject("total_amount", amount.toString());// 订单金额
					view.addObject("code_msg", "无效订单信息");// 状态信息
					view.addObject("jump", "");// 跳转
					return view;
				}

				JSONObject pays = JSONObject.parseObject(res.get(0).getDatas());
				String respCode = front.get("respCode");// 应答码，00表示成功；
				if ("00".equals(respCode)) {
					ModelAndView view = back_return(true);
					view.addObject("out_trade_no", front.get("orderId"));// 订单号
					view.addObject("grade_time", front.get("txnTime"));// 订单发起时间
					view.addObject("total_amount", amount.toString() + " 元");// 订单金额
					view.addObject("code_msg", "支付成功");// 状态信息
					view.addObject("jump", pays.getString("successUrl"));// 跳转
					return view;
				} else {
					ModelAndView view = back_return(false);
					view.addObject("out_trade_no", front.get("orderId"));// 订单号
					view.addObject("grade_time", front.get("txnTime"));// 订单发起时间
					view.addObject("total_amount", amount.toString() + " 元");// 订单金额
					view.addObject("code_msg", "支付失败");// 状态信息
					view.addObject("jump", pays.getString("failUrl"));// 跳转
					return view;
				}
			}

			ModelAndView view = back_return(false);
			view.addObject("out_trade_no", front.get("orderId"));// 订单号
			view.addObject("grade_time", front.get("txnTime"));// 订单发起时间
			view.addObject("total_amount", front.get("txnAmt") + " 分");// 订单金额
			view.addObject("code_msg", "数据验证错误");// 状态信息
			view.addObject("jump", "");// 跳转
			return view;
		} catch (Exception e) {
			log.error("银联页面转调发送数据处理异常:" + e.getMessage());
			ModelAndView view = back_return(false);
			view.addObject("out_trade_no", "无");// 订单号
			view.addObject("grade_time", "无");// 订单发起时间
			view.addObject("total_amount", "无");// 订单金额
			view.addObject("code_msg", "支付错误:" + e.getMessage());// 状态信息
			view.addObject("jump", "");// 跳转
			return view;
		}
	}

	/**
	 * 支付后转调返回页面
	 * 
	 * @param pay
	 * @return
	 */
	private ModelAndView back_return(boolean pay) {
		if (pay)
			return new ModelAndView("union/success");
		else
			return new ModelAndView("union/fail");
	}

	/**
	 * 发起支付时错误页面
	 * 
	 * @param error
	 * @return
	 */
	private String errorHtml(String error) {
		StringBuffer sf = new StringBuffer();

		sf.append("<!DOCTYPE html><html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=" + "UTF-8"
				+ "\"/><title>error</title></head><body>");
		sf.append("<form id = \"pay_form\" action=\"" + "\" method=\"post\"><div>");

		sf.append("<h1 type=\"text\" style=\"color: red;\">支付发生错误!</h1>");
		sf.append("<h3 type=\"text\" style=\"color: red;\">" + error + "</h3>");

		sf.append("</div></form>");
		sf.append("</body>");
		sf.append("</html>");
		return sf.toString();
	}

	/**
	 * 获取请求参数中所有的信息 当商户上送frontUrl或backUrl地址中带有参数信息的时候，
	 * 这种方式会将url地址中的参数读到map中，会导多出来这些信息从而致验签失败，这个时候可以自行修改过滤掉url中的参数或者使用getAllRequestParamStream方法。
	 * 
	 * @param request
	 * @return
	 */
	public static Map<String, String> getAllRequestParam(final HttpServletRequest request) {
		Map<String, String> res = new HashMap<String, String>();
		Enumeration<?> temp = request.getParameterNames();
		if (null != temp) {
			while (temp.hasMoreElements()) {
				String en = (String) temp.nextElement();
				String value = request.getParameter(en);
				res.put(en, value);
				// 在报文上送时，如果字段的值为空，则不上送<下面的处理为在获取所有参数数据时，判断若值为空，则删除这个字段>
				if (null == res.get(en) || "".equals(res.get(en))) {
					// System.out.println("======为空的字段名===="+en);
					res.remove(en);
				}
			}
		}
		return res;
	}

	/**
	 * 业务方回调
	 * 
	 * @param url
	 * @param orderId
	 * @param orderStatus
	 * @return
	 */
	private String returnBack(String orderSid, String amount, String code, String url, String payType) {
		try {
			// Map<String, String> map = new HashMap<String, String>();
			JSONObject map = new JSONObject();
			map.put("sign",
					SignUtil.encryption(new SimpleDateFormat("yyyy-MM-dd").format(new Date()), SignParam.CHANNEL_CODE));
			map.put("payType", payType);// 支付方式代码，1直连、2微信、3银联
			map.put("incomePrice", amount);// 支付金额，单位：元
			map.put("orderSn", orderSid);// 订单号（后台的订单号）
			map.put("code", code);// 001,支付成功;002,核保成功（可以通知前台打单了）;003,支付失败;004,核保失败
			log.info("业务方回调参数:" + JSONObject.toJSONString(map));
			String res = OkHttp.postByJson(url, map.toJSONString());
			log.info("业务方回调返回:" + res);
			return res;
		} catch (Exception e) {
			return "回调异常:" + e.getMessage();
		}
	}

}
